/// 迭代器与闭包
/*
Rust 的设计灵感来源于很多现存的语言和技术。其中一个显著的影响就是 函数式编程（functional programming）。
函数式编程风格通常包含将函数作为参数值或其他函数的返回值、将函数赋值给变量以供之后执行等等。
*/
/// 闭包：可以捕获环境的匿名函数
/*
Rust 的 闭包（closures）是可以保存进变量或作为参数传递给其他函数的匿名函数。可以在一个地方创建闭包，
然后在不同的上下文中执行闭包运算。不同于函数，闭包允许捕获调用者作用域中的值。
我们将展示闭包的这些功能如何复用代码和自定义行为。
*/
use std::thread;
use std::time::Duration;

fn simulated_expensive_calculation(intensity: u32) -> u32 {
    println!("calculating slowly...");
    thread::sleep(Duration::from_secs(2));
    intensity
}


fn main() {
    use std::thread;
    use std::time::Duration;

    let expensive_closure = |num| {
        println!("calculating slowly...");
        thread::sleep(Duration::from_secs(2));
        num
    };
    expensive_closure(5);
}





fn main() {
    use std::thread;
    use std::time::Duration;

    fn simulated_expensive_calculation(num: u32) -> u32 {
        println!("calculating slowly...");
        thread::sleep(Duration::from_secs(2));
        num
    }

    fn generate_workout(intensity: u32, random_number: u32) {
        let expensive_result =
            simulated_expensive_calculation(intensity);

        if intensity < 25 {
            println!(
                "Today, do {} pushups!",
                expensive_result
            );
            println!(
                "Next, do {} situps!",
                expensive_result
            );
        } else {
            if random_number == 3 {
                println!("Take a break today! Remember to stay hydrated!");
            } else {
                println!(
                    "Today, run for {} minutes!",
                    expensive_result
                );
            }
        }
    }
}


fn main() {
    use std::thread;
    use std::time::Duration;

    fn generate_workout(intensity: u32, random_number: u32) {
        let expensive_closure = |num| {
            println!("calculating slowly...");
            thread::sleep(Duration::from_secs(2));
            num
        };

        if intensity < 25 {
            println!(
                "Today, do {} pushups!",
                expensive_closure(intensity)
            );
            println!(
                "Next, do {} situps!",
                expensive_closure(intensity)
            );
        } else {
            if random_number == 3 {
                println!("Take a break today! Remember to stay hydrated!");
            } else {
                println!(
                    "Today, run for {} minutes!",
                    expensive_closure(intensity)
                );
            }
        }
    }
}


/// 闭包类型推断和标注
/*
闭包不要求像 fn 函数那样在参数和返回值上注明类型。函数中需要类型标注是因为他们是暴露给用户的显式接口的一部分。
严格的定义这些接口对于保证所有人都认同函数使用和返回值的类型来说是很重要的。但是闭包并不用于这样暴露在外的接口：
他们储存在变量中并被使用，不用命名他们或暴露给库的用户调用。
*/
fn main() {
    // 以下两种写法效果等同
    fn simulated_expensive_calculation(num: u32) -> u32 {
        println!("calculating slowly...");
        thread::sleep(Duration::from_secs(2));
        num
    }
    // 闭包写法
    let expensive_closure = |num| {
        println!("calculating slowly...");
        thread::sleep(Duration::from_secs(2));
        num
    };
}



/// 使用迭代器处理元素序列
/*
迭代器模式允许你对一个序列的项进行某些处理。迭代器（iterator）负责遍历序列中的每一项和决定序列何时结束的逻辑。
当使用迭代器时，我们无需重新实现这些逻辑。
*/
fn main() {
    let v1 = vec![1, 2, 3];

    let v1_iter = v1.iter();

    for val in v1_iter {
        println!("Got: {}", val);
    }
}

/// Iterator trait 和 next 方法
// next 是 Iterator 实现者被要求定义的唯一方法。next 一次返回迭代器中的一个项，封装在 Some 中，
// 当迭代器结束时，它返回 None。
fn main() {
    #[test]
    fn iterator_demonstration() {
        let v1 = vec![1, 2, 3];
        // 注意 v1_iter 需要是可变的：在迭代器上调用 next 方法改变了迭代器中用来记录序列位置的状态
        let mut v1_iter = v1.iter();

        assert_eq!(v1_iter.next(), Some(&1));
        assert_eq!(v1_iter.next(), Some(&2));
        assert_eq!(v1_iter.next(), Some(&3));
        assert_eq!(v1_iter.next(), None);

        // 使用函数stream流式方法
        let v2: Vec<_> = v1.iter().map(|x| x + 1).collect();
        assert_eq!(v2, vec![2, 3, 4]);
    }
}

///
#[derive(PartialEq, Debug)]
struct Shoe {
    size: u32,
    style: String,
}

fn shoes_in_my_size(shoes: Vec<Shoe>, shoe_size: u32) -> Vec<Shoe> {
    // 迭代器的 filter 方法获取一个使用迭代器的每一个项并返回布尔值的闭包。如果闭包返回 true，其值将会包含在
    // filter 提供的新迭代器中。如果闭包返回 false，其值不会包含在结果迭代器中。
    shoes.into_iter()
        .filter(|s| s.size == shoe_size)
        .collect()
}


///
#[test]
fn using_other_iterator_trait_methods() {
    let sum: u32 = Counter::new()
        .zip(Counter::new().skip(1))
        .map(|(a, b)| a * b)
        .filter(|x| x % 3 == 0)
        .sum();
    assert_eq!(18, sum);
}


/// 性能对比：循环 VS 迭代器。结论： 迭代器性能更好！！！
// 迭代器，作为一个高级的抽象，被编译成了与手写的底层代码大体一致性能代码。
// 迭代器是 Rust 的 零成本抽象（zero-cost abstractions）之一，它意味着抽象并不会引入运行时开销